/*
 * DevicesLed.c
 *
 *      Author: Honrun
 */

#include "gd32f30x.h"
#include "string.h"
#include "DevicesLed.h"



static void vLedPWMInit(void);


LedInfoType st_typeLedInfo;

/* 周期调用计数（调用频率为10k） */
volatile uint32_t st_uiLedTickCnt = 0;
volatile uint32_t st_uiLedSosCnt = 0;
/* 呼吸档位 */
volatile static int16_t st_sGrade = 0;



void vLedInit(void)
{
    /* enable the LED GPIO clock */
    rcu_periph_clock_enable(RCU_GPIOB);

    vLedOpen(LED_CHANNEL_ALL);

    /* configure LED GPIO pin */
    gpio_init(LED_1_GPIO_Port, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, LED_1_Pin);

    vLedPWMInit();

    st_typeLedInfo.user1.driveMode = LED_DRIVE_PWM;
    st_typeLedInfo.user1.periph = TIMER2;
    st_typeLedInfo.user1.channel = TIMER_CH_3;

    vLedBreathe(LED_CHANNEL_ALL);
}

static void vLedPWMInit(void)
{
    timer_oc_parameter_struct timer_ocintpara = {0};

    /* CHx configuration in PWM mode */
    timer_ocintpara.outputstate  = TIMER_CCX_ENABLE;
    timer_ocintpara.outputnstate = TIMER_CCXN_DISABLE;
    timer_ocintpara.ocpolarity   = TIMER_OC_POLARITY_LOW;
    timer_ocintpara.ocnpolarity  = TIMER_OCN_POLARITY_LOW;
    timer_ocintpara.ocidlestate  = TIMER_OC_IDLE_STATE_HIGH;
    timer_ocintpara.ocnidlestate = TIMER_OCN_IDLE_STATE_HIGH;
    timer_channel_output_config(TIMER2, TIMER_CH_3, &timer_ocintpara);

    /* CH0 configuration in PWM mode0,duty cycle 0% */
    timer_channel_output_pulse_value_config(TIMER2, TIMER_CH_3, 0);
    timer_channel_output_mode_config(TIMER2, TIMER_CH_3, TIMER_OC_MODE_PWM0);
    timer_channel_output_shadow_config(TIMER2, TIMER_CH_3, TIMER_OC_SHADOW_ENABLE);
}

void vLedOpen(uint32_t uiChannel)
{
    if(uiChannel & LED_CHANNEL_1)
    {
        gpio_bit_reset(LED_1_GPIO_Port, LED_1_Pin);
    }
}

void vLedClose(uint32_t uiChannel)
{
    if(uiChannel & LED_CHANNEL_1)
    {
        gpio_bit_set(LED_1_GPIO_Port, LED_1_Pin);
    }
}

void vLedRevesal(uint32_t uiChannel)
{
    if(uiChannel & LED_CHANNEL_1)
    {
        GPIO_OCTL(LED_1_GPIO_Port) ^= LED_1_Pin;
    }
}

static void vLedDutySet(LedType *ptypeLed, float fDuty)
{
    if(ptypeLed->driveMode == LED_DRIVE_NULL)
        return;

    /* 限制占空比在： 0% - 100% */
    fDuty = (fDuty < 0.0f) ? 0.0f : ((fDuty > 1.0f) ? 1.0f : fDuty);

    /* PWM 模式 */
    if(ptypeLed->driveMode == LED_DRIVE_PWM)
    {
        /* fDuty: 百分比（0.0f - 1.0f） */
        timer_channel_output_pulse_value_config(ptypeLed->periph, ptypeLed->channel, TIMER_CAR(ptypeLed->periph) * fDuty);
    }
    /* 普通IO 模式 */
    else
    {
        (fDuty <= 0.0f) ? vLedClose(ptypeLed->channel) : vLedOpen(ptypeLed->channel);
    }
}

/*
 * Return:      void
 * Parameters:  usChannel: LED通道; usChannel: 状态; usChannel: 闪烁次数/或者占空比;
 * Description: 设置LED状态
 */
void vLedStatusSet(LedChannelEnum usChannel, LedStateEnum enumStatus, uint8_t ucCntOrDuty)
{
    if(usChannel & LED_CHANNEL_1)
    {
        st_typeLedInfo.user1.state    = enumStatus;
        st_typeLedInfo.user1.cnt      = ucCntOrDuty * 2 + 1;
        st_typeLedInfo.user1.duty     = ucCntOrDuty % 101;
    }
}

/*
 * Return:      void
 * Parameters:  *ptypeLed: LED信息结构体
 * Description: LED状态刷新
 */
static void vLedStateMachine(LedType *ptypeLed)
{
    uint32_t uiPeriod;

    switch(ptypeLed->state)
    {
        /* 关闭 */
        case LED_DISABLE:
            vLedDutySet(ptypeLed, 0.0f);
            ptypeLed->state = LED_IDLE;
            break;

        /* 常亮 */
        case LED_ENABLE:
            vLedDutySet(ptypeLed, LED_HIGH_DUTY);
            ptypeLed->state = LED_IDLE;
            break;

        /* 常亮 - 低亮 */
        case LED_ENABLE_LOW:
            vLedDutySet(ptypeLed, LED_LOW_DUTY);
            ptypeLed->state = LED_IDLE;
            break;

        /* 呼吸 */
        case LED_BREATHE:
            /* 符合人类生理的呼吸曲线：y = x * x */
            vLedDutySet(ptypeLed, st_sGrade < 0 ? 0 : st_sGrade * st_sGrade * (1.0f / 125.0f / 125.0f));
            break;

        /* 固定占空比 */
        case LED_DUTY:
            vLedDutySet(ptypeLed, ptypeLed->duty / 100.0f);
            ptypeLed->state = LED_IDLE;
            break;

        /* 快速频率---持续闪烁、闪烁后常亮、闪烁后关闭 */
        case LED_FLASH_FAST:
        case LED_FLASH_FAST_ENABLE_CNT:
        case LED_FLASH_FAST_DISABLE_CNT:
        /* 低速频率---持续闪烁、闪烁后常亮、闪烁后关闭 */
        case LED_FLASH_SLOW:
        case LED_FLASH_SLOW_ENABLE_CNT:
        case LED_FLASH_SLOW_DISABLE_CNT:
            uiPeriod = (ptypeLed->state >= LED_FLASH_SLOW) ? (LED_FLASH_SLOW_PERIOD / 2) : (LED_FLASH_FAST_PERIOD / 2);

            if((st_uiLedTickCnt % uiPeriod) == 0)
            {
                vLedDutySet(ptypeLed, ((st_uiLedTickCnt / uiPeriod) & 1) ? 1.0f : 0.0f);

                if((ptypeLed->state != LED_FLASH_FAST) && (ptypeLed->state != LED_FLASH_SLOW) && ((ptypeLed->cnt--) <= 0))
                {
                    ptypeLed->state = ((ptypeLed->state == LED_FLASH_FAST_ENABLE_CNT) || (ptypeLed->state == LED_FLASH_SLOW_ENABLE_CNT)) ? LED_ENABLE : LED_DISABLE;
                }
            }
            break;

        default : break;
    }
}

/*
 * Return:      void
 * Parameters:  void
 * Description: LED心跳计数 + 呼吸状态机
 */
static void vLedIncTick(void)
{
    /* 呼吸方向 */
    static int8_t st_cDirection = 1;

    /* 所有LED使用同一个状态机变量，以方便实现一致的闪烁步调 */
    st_uiLedTickCnt += LED_EXECUTION_PERIOD;

    /* 更新呼吸模式占空比 */
    {
        st_sGrade += st_cDirection;
        /* 之所以把档位设置的比 0 小一点，是为了在呼吸状态时，LED能够彻底熄灭一段时间 */
        st_cDirection = (st_sGrade >= 125) ? -1 : ((st_sGrade <= -25) ? 1 : st_cDirection);
    }
}

/* 20ms调用一次 */
void vLedMachine(void)
{
    LedType *ptypeLed = (LedType *)(&st_typeLedInfo);
    int8_t i;

    /* 更新1次计数值 */
    vLedIncTick();

    /* 扫描所有的led状态 */
    for(i = 0; i < (sizeof(LedInfoType) / sizeof(LedType)); ++i)
    {
        vLedStateMachine(ptypeLed++);
    }
}

LedInfoType *ptypeLedGetInfo(void)
{
    return &st_typeLedInfo;
}
